package com.example.schedules;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.entity.Post;
import com.example.service.PostService;
import com.example.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * 加一个定时器，把缓存的数据同步到数据库MySQL里，实现数据同步
 *
 * @Author 林必昭
 * @Date 2019/9/7 9:45
 */
@Slf4j
@Component
public class ScheduledTasks {

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    PostService postService;


    /**
     * Cron表达式通过通配符的方式实现在某个时间点执行任务，如：
     * "0/15"在秒域意思是每分钟的0,15,30和45秒同步更新
     * "5/15"在分域意思是没小时的5,20,35和50分同步更新
     */
//    @Scheduled(cron = "0 0/30 9-17 * * ?")  //朝九晚五工作时间内每半小时
//    @Scheduled(cron = "0 0 2 * * ?")  //每天2点同步
    @Scheduled(cron = "0 0/1 * * * *")  //一分钟(测试用)
    public void postViewCountSync(){
        /**
         * 同步阅读的列表，我们用keys命令，实际上redis的缓存越来越大的时候，使用keys命令可能会带来阻塞
         * 服务器的问题，理论上需要使用scan命令，scan命令用于迭代当前数据库的key的集合
         */
        //todo 用scan命令实现
        Set<String> keys = redisTemplate.keys("rank_post_*");  //匹配所以的rank_post_postId
        List<String> ids = new ArrayList<>();

        for (String key : keys){
            //因为key为"rank_post_"+post.getId(),
            String postId = key.substring("rank_post_".length());
            //判断key是否存在
            if (redisUtil.hHasKey("rank_post_"+postId,"post:viewCount")){
                ids.add(postId);
            }
        }
        if (ids.isEmpty()) return;
        //如果不为空，通过遍历ids的id，将文章查询出来
        List<Post> posts = postService.list(new QueryWrapper<Post>().in("id", ids));

        //记载需要同步的key
        List<String> syncKeys = new ArrayList<>();

        Iterator<Post> it = posts.iterator();
        while (it.hasNext()){
            Post post = it.next();
            Object count = redisUtil.hget("rank_post_" + post.getId(), "post:viewCount");
            if (count!=null){
                post.setViewCount(Integer.valueOf(count.toString()));
                syncKeys.add("rank_post_"+post.getId());
            }else {
                //不需要同步的
            }
        }
        if (posts.isEmpty()) return;
        //批量插入数据库
        boolean isSuccess = postService.updateBatchById(posts);
        if (isSuccess){
            //删除缓存中的阅读数量，防止重复同步
            for (Post post:posts){
                redisUtil.hdel("rank_post_"+post.getId(),"post:viewCount");
            }
        }
        log.info("同步文章阅读成功------> 同步的key有{}",syncKeys);
    }
}
